﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace SCG.TurboSprite.TileBased
{
    [ToolboxBitmap(typeof(TileBasedSpriteSurface), "TileBasedSpriteSurface")]
    public partial class TileBasedSpriteSurface : SpriteSurface
    {
        //constructors
        public TileBasedSpriteSurface()
        {
            InitializeComponent();
        }
        public TileBasedSpriteSurface(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }

        //Events
        public event EventHandler<TileEventArgs> TileClicked;

        //The mapset we're drawing
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public MapSet MapSet
        {
            get
            {
                return _mapSet;
            }
            set
            {
                _mapSet = value;
            }
        }   

        //Show the points of tiles?
        public bool ShowPoints
        {
            get
            {
                return _showPoints;
            }
            set
            {
                _showPoints = value;
            }
        }

        //Color of zones
        public Color ColorLandTiles
        {
            get
            {
                return _colorLandTiles;
            }
            set
            {
                _colorLandTiles = value;
            }
        }
        public Color ColorSeaTiles
        {
            get
            {
                return _colorSeaTiles;
            }
            set
            {
                _colorSeaTiles = value;
            }
        }

        //Border of land zones
        public Color BorderColorLand
        {
            get
            {
                return _borderColorLand;
            }
            set
            {
                _borderColorLand = value;
            }
        }
        public int BorderWidthLand
        {
            get
            {
                return _borderWidthLand;
            }
            set
            {
                _borderWidthLand = value;
            }
        }
        public Color BorderColorSea
        {
            get
            {
                return _borderColorSea;
            }
            set
            {
                _borderColorSea = value;
            }
        }
        public int BorderWidthSea
        {
            get
            {
                return _borderWidthSea;
            }
            set
            {
                _borderWidthSea = value;
            }
        }

        //Outline effects of land zones
        public int OutlineCountLand
        {
            get
            {
                return _outlinesLand;
            }
            set
            {
                _outlinesLand = value;
            }
        }
        public int OutlineWidthLand
        {
            get
            {
                return _outlineWidthLand;
            }
            set
            {
                _outlineWidthLand = value;
            }
        }
        public int OutlineFadeLand
        {
            get
            {
                return _outlineFadeLand;
            }
            set
            {
                _outlineFadeLand = value;
            }
        }

        //Shore outline effect
        public int ShoreCount
        {
            get
            {
                return _shortCount;
            }
            set
            {
                _shortCount = value;
            }
        }
        public int ShoreWidth
        {
            get
            {
                return _shoreWidth;
            }
            set
            {
                _shoreWidth = value;
            }
        }
        public int ShoreFade
        {
            get
            {
                return _shoreFade;
            }
            set
            {
                _shoreFade = value;
            }
        }

        //Cursor
        public bool CursorVisible
        {
            get
            {
                return _cursorVisible;
            }
            set
            {
                _cursorVisible = value;
                SetCursorPen();
            }
        }
        public Color CursorColor
        {
            get
            {
                return _cursorColor;
            }
            set
            {
                _cursorColor = value;
                SetCursorPen();
            }
        }
        public int CursorWidth
        {
            get
            {
                return _cursorWidth;
            }
            set
            {
                _cursorWidth = value;
                SetCursorPen();
            }
        }

        //The selected tile
        public Tile SelectedTile { get; set; }

        //Center on a tile
        public void CenterOnTile(Tile tile)
        {
            OffsetX = tile.Center.X - Width / 2;
            OffsetY = tile.Center.Y - Height / 2;
        }

        //private members
        private MapSet _mapSet = null;
        private bool _showPoints = false;
        private Color _borderColorLand = Color.White;
        private int _borderWidthLand = 2;
        private Color _borderColorSea = Color.Aqua;
        private int _borderWidthSea = 2;
        private int _outlinesLand = 1;
        private int _outlineWidthLand = 12;
        private int _outlineFadeLand = 10;
        private Color _colorLandTiles = Color.DarkGoldenrod;
        private Color _colorSeaTiles = Color.DarkBlue;
        public int _shortCount = 2;
        public int _shoreWidth = 12;
        public int _shoreFade = 10;
        private bool _cursorVisible = true;
        private Color _cursorColor = Color.Yellow;
        private int _cursorWidth = 3;
        private Pen _cursorPen = null;

        //Render tiles
        protected override void DoBeforeSpriteRender(Graphics g)
        {
            if (_mapSet == null)
                return;

            Rectangle viewport = new Rectangle(OffsetX, OffsetY, Width, Height);

            lock (MapSet.Tiles)
            {
                //Render filled polygons for sea tiles
                foreach (Tile tile in MapSet.Tiles)
                    if (tile.TileType == TileType.Sea)
                        if (viewport.IntersectsWith(tile.Bounds))
                            tile.FillBackground(g);

                //Render shorelines
                if (MapSet.Tiles.Count > 0)
                    foreach (List<Segment> path in MapSet.ShorePaths)
                        MapSet.Tiles[0].RenderShorePath(g, path);

                //Render filled polygons for land tiles
                foreach (Tile tile in MapSet.Tiles)  
                    if (tile.TileType == TileType.Land)
                        if (viewport.IntersectsWith(tile.Bounds))
                            tile.FillBackground(g);

                //Render the map decorations
                if (_mapSet.Decorations.Count > 0)
                {
                    foreach (MapDecoration decor in _mapSet.Decorations)
                    {
                        Rectangle rect = new Rectangle(decor.X, decor.Y, decor.Bitmap.Width, decor.Bitmap.Height);
                        if (viewport.IntersectsWith(rect))
                        {
                            int w = decor.Bitmap.Width;
                            int h = decor.Bitmap.Height;
                            int dx = (int)(decor.X - OffsetX);
                            int dy = (int)(decor.Y - OffsetY);
                            if (decor.ImageAttributes == null)
                                g.DrawImage(decor.Bitmap, dx, dy);
                            else
                                g.DrawImage(decor.Bitmap, new Rectangle(dx, dy, w, h), 0, 0, w, h, GraphicsUnit.Pixel, decor.ImageAttributes);
                        }
                    }
                }

                //Render sea zones first, then land zones
                foreach (Tile tile in MapSet.Tiles)
                    if (tile.TileType == TileType.Sea)
                        if (viewport.IntersectsWith(tile.Bounds))
                            tile.Render(g);                     

                //finally land zones
                foreach (Tile tile in MapSet.Tiles)
                    if (tile.TileType == TileType.Land)
                        if (viewport.IntersectsWith(tile.Bounds))
                            tile.Render(g);

                //Render points
                if (ShowPoints)
                {
                    int x;
                    int y;
                    foreach (Tile tile in MapSet.Tiles)
                        if (viewport.Contains(tile.Bounds))
                        {
                            foreach (Point pt in tile.Points)
                            {
                                x = pt.X - OffsetX;
                                y = pt.Y - OffsetY;
                                g.DrawEllipse(Pens.White, x - 2, y - 2, 4, 4);
                            }
                        }
                }

                //Render the selected tile
                if (CursorVisible && SelectedTile != null)
                    if (viewport.IntersectsWith(SelectedTile.Bounds))
                    {
                        if (_cursorPen == null)
                            _cursorPen = new Pen(_cursorColor, _cursorWidth);
                        g.DrawPolygon(_cursorPen, SelectedTile._pointArray);
                    }
            }
        }

        //Adjust the cursor pen when properties change
        private void SetCursorPen()
        {
            if (_cursorPen != null)
            {
                _cursorPen.Color = _cursorColor;
                _cursorPen.Width = _cursorWidth;
            }
        }

        //trigger a TileSelected event
        protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
        {
            base.OnMouseUp(e);
            Point pt = new Point(e.X, e.Y);
            pt.Offset(OffsetX, OffsetY);
            foreach(Tile tile in MapSet.Tiles)
                if (MapSet.PointInPolygon(pt, tile.Points))
                {
                    SelectedTile = tile;
                    if (TileClicked != null)     
                        TileClicked(this, new TileEventArgs(tile));
                    return;
                }
        }

        //Click on a tile
        public void ClickOnTile(Tile tile)
        {
            SelectedTile = tile;
            if (TileClicked != null)
                TileClicked(this, new TileEventArgs(tile));
        }
    }

    //Events that carry a Tile parameter
    public class TileEventArgs : EventArgs
    {
        public TileEventArgs(Tile tile)
            : base()
        {
            _tile = tile;
        }

        public Tile Tile
        {
            get
            {
                return _tile;
            }
        }

        private Tile _tile;
    }
}
